package utils

import (
	"fmt"
	"log"
	"net"
	"os"
	"os/exec"
	"runtime"
	"strconv"
	"strings"
	"time"
)

// CheckAndClearPort 检查端口是否被占用，如果占用则尝试清理
func CheckAndClearPort(port int) error {
	log.Printf("🔍 检查端口 %d 是否被占用...", port)

	// 检查端口是否被占用
	if !IsPortInUse(port) {
		log.Printf("✅ 端口 %d 可用", port)
		return nil
	}

	log.Printf("⚠️  端口 %d 被占用，尝试清理...", port)

	// 获取占用端口的进程
	pids, err := GetProcessIDsByPort(port)
	if err != nil {
		log.Printf("❌ 获取端口 %d 占用进程失败: %v", port, err)
		return fmt.Errorf("获取端口占用进程失败: %w", err)
	}

	if len(pids) == 0 {
		log.Printf("🤔 端口 %d 被占用但未找到占用进程", port)
		return fmt.Errorf("端口被占用但未找到占用进程")
	}

	// 杀死占用端口的进程
	for _, pid := range pids {
		log.Printf("🔥 尝试结束进程 PID: %d", pid)
		if err := KillProcess(pid); err != nil {
			log.Printf("❌ 结束进程 %d 失败: %v", pid, err)
		} else {
			log.Printf("✅ 进程 %d 已结束", pid)
		}
	}

	// 等待端口释放
	log.Printf("⏳ 等待端口 %d 释放...", port)
	for i := 0; i < 10; i++ {
		time.Sleep(500 * time.Millisecond)
		if !IsPortInUse(port) {
			log.Printf("✅ 端口 %d 已释放", port)
			return nil
		}
	}

	log.Printf("❌ 端口 %d 仍被占用，清理失败", port)
	return fmt.Errorf("端口 %d 清理失败", port)
}

// IsPortInUse 检查端口是否被占用
func IsPortInUse(port int) bool {
	// 尝试监听端口
	ln, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
	if err != nil {
		return true // 端口被占用
	}
	ln.Close()
	return false // 端口可用
}

// GetProcessIDsByPort 根据端口获取占用的进程ID
func GetProcessIDsByPort(port int) ([]int, error) {
	var pids []int

	switch runtime.GOOS {
	case "darwin", "linux":
		// macOS和Linux使用lsof命令
		cmd := exec.Command("lsof", "-ti", fmt.Sprintf(":%d", port))
		output, err := cmd.Output()
		if err != nil {
			return pids, nil // 没有找到占用进程
		}

		lines := strings.Split(strings.TrimSpace(string(output)), "\n")
		for _, line := range lines {
			if line != "" {
				if pid, err := strconv.Atoi(line); err == nil {
					pids = append(pids, pid)
				}
			}
		}

	case "windows":
		// Windows使用netstat命令
		cmd := exec.Command("netstat", "-ano")
		output, err := cmd.Output()
		if err != nil {
			return pids, err
		}

		lines := strings.Split(string(output), "\n")
		for _, line := range lines {
			if strings.Contains(line, fmt.Sprintf(":%d", port)) && strings.Contains(line, "LISTENING") {
				fields := strings.Fields(line)
				if len(fields) >= 5 {
					if pid, err := strconv.Atoi(fields[4]); err == nil {
						pids = append(pids, pid)
					}
				}
			}
		}
	}

	return pids, nil
}

// KillProcess 结束指定PID的进程
func KillProcess(pid int) error {
	process, err := os.FindProcess(pid)
	if err != nil {
		return fmt.Errorf("找不到进程 %d: %w", pid, err)
	}

	switch runtime.GOOS {
	case "darwin", "linux":
		// Unix系统使用SIGTERM信号
		if err := process.Signal(os.Interrupt); err != nil {
			// 如果SIGTERM失败，使用SIGKILL强制结束
			return process.Kill()
		}

	case "windows":
		// Windows直接结束进程
		return process.Kill()
	}

	return nil
}

// CheckAndClearPorts 批量检查和清理多个端口
func CheckAndClearPorts(ports []int) error {
	log.Println("🔍 开始批量检查端口占用情况...")

	var errors []string

	for _, port := range ports {
		if err := CheckAndClearPort(port); err != nil {
			errors = append(errors, fmt.Sprintf("端口%d: %v", port, err))
		}
	}

	if len(errors) > 0 {
		return fmt.Errorf("部分端口清理失败: %s", strings.Join(errors, "; "))
	}

	log.Println("✅ 所有端口检查完成")
	return nil
}

// GetAvailablePort 获取一个可用的端口（兼容旧版本）
func GetAvailablePort() (string, error) {
	listener, err := net.Listen("tcp", ":0")
	if err != nil {
		return "", err
	}
	defer listener.Close()

	addr := listener.Addr().(*net.TCPAddr)
	return strconv.Itoa(addr.Port), nil
}

// GetAvailablePortInRange 在指定范围内获取一个可用的端口
func GetAvailablePortInRange(startPort int) (int, error) {
	for port := startPort; port <= 65535; port++ {
		if !IsPortInUse(port) {
			return port, nil
		}
	}
	return 0, fmt.Errorf("未找到可用端口")
}

// WaitForPortReady 等待端口准备就绪
func WaitForPortReady(port int, timeout time.Duration) error {
	log.Printf("⏳ 等待端口 %d 准备就绪...", port)

	deadline := time.Now().Add(timeout)
	for time.Now().Before(deadline) {
		conn, err := net.DialTimeout("tcp", fmt.Sprintf("localhost:%d", port), 100*time.Millisecond)
		if err == nil {
			conn.Close()
			log.Printf("✅ 端口 %d 已就绪", port)
			return nil
		}
		time.Sleep(100 * time.Millisecond)
	}

	return fmt.Errorf("等待端口 %d 就绪超时", port)
}
